package com.dynamic.sync.toolkit.mongo.sync.service.impl;

import com.dynamic.sync.toolkit.mongo.MongoClientProvider;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncFromEnvReq;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncFromPrdReq;
import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.dynamic.sync.toolkit.EnvType;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncFromDevReq;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncFromPreReq;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncFromTestReq;
import com.dynamic.sync.toolkit.mongo.sync.request.SyncSourceToTargetReq;
import com.dynamic.sync.toolkit.mongo.sync.service.MongoSyncService;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author ZonLen since on 2021/6/19 下午8:50
 */
@Service
public class MongoSyncServiceImpl implements MongoSyncService {

  @Autowired
  private MongoClientProvider mongoClientProvider;

  private static final AtomicBoolean LOCK = new AtomicBoolean(true);

  @Override
  public void syncSourceToTarget(SyncSourceToTargetReq req) {
    if (!LOCK.get()) {
      return;
    }
    try {
      LOCK.set(false);
      final MongoDatabase sourceDb = mongoClientProvider
          .mongoDatabase(req.sourceEnv());
      final MongoDatabase targetDb = mongoClientProvider
          .mongoDatabase(req.targetEnv());
      final MongoCollection<Document> collection = targetDb.getCollection(req.getSourceDocumentName());
      final BasicDBObject bson = new BasicDBObject();
      final FindIterable<Document> documents = sourceDb.getCollection(req.getTargetDocumentName()).find();
      sourceToTarget(collection, bson, documents, req.getGroupPrimaryKey());
    } finally {
      LOCK.set(true);
    }
  }

  @Override
  public void syncFromPrd(SyncFromPrdReq req) {
    sync(req, EnvType.prd);
  }

  @Override
  public void syncFromDev(SyncFromDevReq req) {
    sync(req, EnvType.dev);
  }

  @Override
  public void syncFromPre(SyncFromPreReq req) {
    sync(req, EnvType.pre);
  }

  @Override
  public void syncFromTest(SyncFromTestReq req) {
    sync(req, EnvType.test);
  }

  private void sync(SyncFromEnvReq req, EnvType defaultEnv) {
    if (!LOCK.get()) {
      return;
    }
    try {
      LOCK.set(false);
      final MongoDatabase sourceDb = mongoClientProvider
          .mongoDatabase(defaultEnv);
      final MongoDatabase targetDb = mongoClientProvider
          .mongoDatabase(req.targetEnv());
      final MongoCollection<Document> collection = targetDb.getCollection(req.getDocumentName());
      final BasicDBObject bson = new BasicDBObject();
      final FindIterable<Document> documents = sourceDb.getCollection(req.getDocumentName()).find();
      sourceToTarget(collection, bson, documents, req.getGroupPrimaryKey());
    } finally {
      LOCK.set(true);
    }
  }

  private void sourceToTarget(MongoCollection<Document> collection, BasicDBObject bson,
      FindIterable<Document> documents, List<String> groupPrimaryKey) {
    documents.forEach((Block<? super Document>) document -> {
      for (String key : groupPrimaryKey) {
        bson.put(key, document.get(key));
      }
      System.out.println(document);
      collection.findOneAndDelete(bson);
      collection.insertOne(document);
    });
  }

}
